#include <stdio.h>          // 标准输入输出
#include <stdlib.h>         // 标准函数库
#include <string.h>         // 字符串处理(操作字符数组)

#include "ohos_init.h"      // 用于初始化服务(services)和功能(features)
#include "cmsis_os2.h"      // CMSIS-RTOS API V2

#include "wifi_connecter.h" // easy wifi (station模式)
#include "mqtt_task.h"      // MQTT接口

#include "iot_gpio.h"
#include "hi_gpio.h"
// 海思SDK接口：IoT硬件设备操作接口-IO
// 海思SDK接口，以hi_io_set_func(...)
#include "hi_io.h"
#include "hi_pwm.h"     // 海思 Pegasus SDK：IoT硬件设备操作接口-PWM

// 定义GPIO引脚
#define SCK_GPIO 0
#define DOUT_GPIO 1

#define GapValue 205
// float Weight=0;
uint32_t Weight_Maopi = 0;
uint32_t HX711_Buffer = 0;
int32_t Weight_Shiwu = 0;

// 定义一个宏，用于标识SSID。请根据实际情况修改
#define PARAM_HOTSPOT_SSID "Redmi"

// 定义一个宏，用于标识密码。请根据实际情况修改
#define PARAM_HOTSPOT_PSK "264557abc"

// 定义一个宏，用于标识加密方式
#define PARAM_HOTSPOT_TYPE WIFI_SEC_TYPE_PSK

// 定义一个宏，用于标识MQTT服务器IP地址。请根据实际情况修改
#define PARAM_SERVER_ADDR "182.92.158.237"

// 定义一个宏，用于标识MQTT服务器端口
#define PARAM_SERVER_PORT "1883"


uint32_t Hx711_Read(void)
{
    unsigned long count;
    unsigned char i;
    IotGpioValue value = IOT_GPIO_VALUE0;
    IoTGpioGetInputVal(DOUT_GPIO, &value);
    osDelay(0.001);
    IoTGpioSetOutputVal(SCK_GPIO, IOT_GPIO_VALUE0); // 输出高电平
    osDelay(0.001);
    count = 0;
    // 获取GPIO5引脚的输入电平（1高电平，0低电平）
    // 调用IoTGpioGetInputVal接口
    do
    {
        IoTGpioGetInputVal(DOUT_GPIO, &value);
    } while (value);
    for (i = 0; i < 24; i++)
    {
        // IoTGpioSetOutputVal(SCK_GPIO, i%2?IOT_GPIO_VALUE1:IOT_GPIO_VALUE0); // 状态验证
        IoTGpioSetOutputVal(SCK_GPIO, IOT_GPIO_VALUE1); // 输出高电平
        osDelay(0.001);
        count = count << 1;                             // 左移一位
        IoTGpioSetOutputVal(SCK_GPIO, IOT_GPIO_VALUE0); // 输出低电平
        osDelay(0.001);
        IoTGpioGetInputVal(DOUT_GPIO, &value);
        // printf("%d", value);
        if (value)
        {
            count++;
        }
    }
    IoTGpioSetOutputVal(SCK_GPIO, IOT_GPIO_VALUE1);
    count = count ^ 0x800000;
    osDelay(0.001);
    IoTGpioSetOutputVal(SCK_GPIO, IOT_GPIO_VALUE0);
    osDelay(0.001);
    return count;
}

int32_t Get_Weight()
{
    HX711_Buffer = Hx711_Read();
    if(HX711_Buffer > Weight_Maopi)
    {
    Weight_Shiwu = HX711_Buffer;
    Weight_Shiwu = Weight_Shiwu - Weight_Maopi;               // 获取实物的AD采样数值。
    Weight_Shiwu = (int32_t)((float)Weight_Shiwu / GapValue); // 计算实物的实际重量
                                                                  // 因为不同的传感器特性曲线不一样，因此，每一个传感器需要矫正这里的GapValue这个除数。
                                                                  // 当发现测试出来的重量偏大时，增加该数值。
																	//如果测试出来的重量偏小时，减小改数值。
    }
    return Weight_Shiwu;
}


// 分频倍数数组
// 40MHz 对应的分频倍数：
static const uint16_t g_tuneFreqs[] = {
    //每个音调的分频倍数
    0,     // 不使用
    38223, // 1046.5Hz  C6(do)
    34052, // 1174.7Hz  D6(re)
    30338, // 1318.5Hz  E6(mi)
    28635, // 1396.9Hz  F6(fa)
    25511, // 1568Hz    G6(so)
    22728, // 1760Hz    A6(la)
    20249, // 1975.5Hz  B6(si)
    51020  // 784Hz     G5(so)低八度
};

// 曲谱音符数组：《两只老虎》。
// 简谱：http://www.jianpu.cn/pu/33/33945.htm
// static const uint8_t g_scoreNotes[] = {
//     //音符 1代表是dou 2是ruai
//     1, 2, 3, 1,        1, 2, 3, 1,        3, 4, 5,  3, 4, 5,
//     5, 6, 5, 4, 3, 1,  5, 6, 5, 4, 3, 1,  1, 8, 1,  1, 8, 1, // 最后两个 5 应该是低八度的，链接图片中的曲谱不对，声音到最后听起来不太对劲
// };

// 曲谱音符数组：《蜜雪冰城主题曲》
static const uint8_t g_scoreNotes[] = {
    //音符 1代表是dou 2是ruai
    3, 5, 5, 6, 5, 3, 1, 1, 2, 3, 3, 2, 1, 2,
    3, 5, 5, 6, 5, 3, 1, 1, 2, 3, 3, 2, 2, 1,
    4, 4, 4, 6, 5, 5, 3, 2,
    3, 5, 5, 6, 5, 3, 1, 1, 2, 3, 3, 2, 2, 1
};

// 曲谱时值数组：《两只老虎》。
// 根据简谱记谱方法转写。
// 4/4拍中下面划一条线是半拍，划两条线是四分之一拍，点是顺延半拍
// static const uint8_t g_scoreDurations[] = {
//     4, 4, 4, 4,        4, 4, 4, 4,        4, 4, 8,  4, 4, 8,
//     3, 1, 3, 1, 4, 4,  3, 1, 3, 1, 4, 4,  4, 4, 8,  4, 4, 8,
// };

// 曲谱时值数组：《蜜雪冰城主题曲》
static const uint8_t g_scoreDurations[] = {
    //节拍
    2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 8,
    2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 8,
    4, 4, 2, 6, 4, 3, 1, 8,
    2, 2, 3, 1, 2, 2, 2, 1, 1, 2, 2, 2, 2, 8
};




// 主线程函数
static void mqttDemoTask(void *arg)
{
    (void)arg;


    // 初始化GPIO模块
    IoTGpioInit(SCK_GPIO);
    IoTGpioInit(DOUT_GPIO);

    // 设置GPIO0为GPIO功能
    hi_io_set_func(SCK_GPIO, HI_IO_FUNC_GPIO_0_GPIO);

    // 设置GPIO0为输出模式
    IoTGpioSetDir(SCK_GPIO, IOT_GPIO_DIR_OUT);

    // 设置GPIO1为GPIO功能
    hi_io_set_func(DOUT_GPIO, HI_IO_FUNC_GPIO_1_GPIO);

    // 设置GPIO1为输入模式
    IoTGpioSetDir(DOUT_GPIO, IOT_GPIO_DIR_IN);

     // 蜂鸣器引脚 设置为 PWM功能
    IoTGpioInit(HI_IO_NAME_GPIO_9);
    hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_PWM0_OUT);
    IoTGpioSetDir(HI_IO_NAME_GPIO_9, IOT_GPIO_DIR_OUT);
    IoTPwmInit(HI_PWM_PORT_PWM0);

    Weight_Maopi = Hx711_Read();
    osDelay(200);
    int floag=0;

    // 连接AP
    // 定义热点配置
    WifiDeviceConfig config = {0};
    // 设置热点配置中的SSID
    strcpy(config.ssid, PARAM_HOTSPOT_SSID);
    // 设置热点配置中的密码
    strcpy(config.preSharedKey, PARAM_HOTSPOT_PSK);
    // 设置热点配置中的加密方式
    config.securityType = PARAM_HOTSPOT_TYPE;
    // 等待100ms
    osDelay(10);
    // 连接到热点
    int netId = ConnectToHotspot(&config);
    // 检查是否成功连接到热点
    if (netId < 0)
    {
        printf("Connect to AP failed!\r\n");
        return;
    }

    // 初始化并启动MQTT任务，连接MQTT服务器
    MqttTaskInit();                                                     // 初始化并启动MQTT任务
    const char *host = PARAM_SERVER_ADDR;                               // MQTT服务器IP地址
    unsigned short port = atoi(PARAM_SERVER_PORT);                      // MQTT服务器端口
    const char *clientId = "project";                               // MQTT客户端ID
    const char *username = "admin";                                        // MQTT服务器用户名
    const char *password = "123";                                        // MQTT服务器密码
    if (MqttTaskConnect(host, port, clientId, username, password) != 0) // 连接MQTT服务器
    {
        // 连接失败，输出错误信息并退出
        printf("Connect to MQTT server failed!\r\n");
        return;
    }

    // 订阅主题
    char *stopic = "Open/devices/hx711/project";            // 主题
    int rc = MqttTaskSubscribe(stopic); // 订阅主题
    if (rc != 0)
    {
        // 订阅失败，输出错误信息并退出
        printf("MQTT Subscribe failed!\r\n");
        return;
    }
    // 输出订阅成功信息
    printf("MQTT Subscribe OK\r\n");

    // 向主题发布一条消息
    char *ptopic = "Open/devices/hx711/project1";                            // 主题
    char *payload = "{\"device_id\":\"hx711\", \"status\":\"online\"}"; // 消息内容
    rc = MqttTaskPublish(ptopic, payload);              // 发布消息
    if (rc != 0)
        printf("MQTT Publish failed!\r\n");             // 发布失败，输出错误信息
    else
        printf("MQTT Publish OK\r\n");                  // 发布成功，输出成功信息
    
    while (1)
    {
        char payload[64] = {0};                                         // 消息内容
        snprintf(payload, sizeof(payload),
                 "{\"device_id\":\"hx711\", \"weight\":\"%d\"}",
                 Get_Weight());
                 if(Weight_Shiwu>0)
                 floag=1;                                      // 获取数据
        int rc = MqttTaskPublish(ptopic, payload);                      // 发布消息
        if (rc != 0)                                                    // 检查是否成功发布消息
            printf("MQTT Publish failed!\r\n");
        else
            printf("MQTT Publish OK\r\n");
            printf("净重量 = %d g\r\n", Weight_Shiwu); // 打印
            if(floag==1&&Weight_Shiwu<5)
            {
                printf("BeeperMusicTask start!\r\n");   // 日志输出

    hi_pwm_set_clock(PWM_CLK_XTAL); // 设置时钟源为外部晶体时钟（40MHz，默认时钟源160MHz）

    // 演奏音乐
    // 使用循环遍历曲谱音符数组
    for (size_t i = 0; i < sizeof(g_scoreNotes)/sizeof(g_scoreNotes[0]); i++) {
        // 获取音符，也就是分频倍数数组元素的下标
        uint32_t tune = g_scoreNotes[i];
        // 获取分频倍数
        uint16_t freqDivisor = g_tuneFreqs[tune];
        // 获取音符时间
        // 适当拉长时间，四分之一拍用时125ms，每小节2s
        uint32_t tuneInterval = g_scoreDurations[i] * (125*1000);
        // 日志输出
        printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval);
        // 开始输出PWM信号，占空比50%freqDivisor/2 占空比设置音量大小
        hi_pwm_start(HI_PWM_PORT_PWM0, freqDivisor/2, freqDivisor);
        // 等待音符时间，参数的单位是微秒（千分之一毫秒）
        usleep(tuneInterval);//等待时长就是节拍时间
        // 停止输出PWM信号
        hi_pwm_stop(HI_PWM_PORT_PWM0);
        // 停止一个音符后，等待20ms，让两次发音有个间隔，听起来更自然一些
        usleep(20*1000);}
            }
        osDelay(100);                                                   // 发布消息间隔1秒。实际上报无需这么频繁
    }


    
}

// 入口函数
static void mqttDemoEntry(void)
{
    // 定义线程属性
    osThreadAttr_t attr;
    attr.name = "mqttDemoTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    // 创建线程
    if (osThreadNew(mqttDemoTask, NULL, &attr) == NULL)
    {
        printf("[mqttDemoEntry] Falied to create mqttDemoTask!\n");
    }
}

// 运行入口函数
SYS_RUN(mqttDemoEntry);
